package com.senyint.imsdk;

import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.ConversationManager;
import org.jivesoftware.smack.PacketInterceptor;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;


import org.jivesoftware.smack.ping.packet.Ping;

import com.senyint.imsdk.listener.SdkHandlerListener;
import com.senyint.imsdk.listener.XMPPConnecionListener;
import com.senyint.imsdk.listener.XMPPIQInterceptor;
import com.senyint.imsdk.listener.XMPPIQListener;
import com.senyint.imsdk.listener.XMPPMessageInterceptor;
import com.senyint.imsdk.listener.XMPPMessageListener;
import com.senyint.imsdk.listener.XMPPPresenceInterceptor;
import com.senyint.imsdk.listener.XMPPPresenceListener;
import com.senyint.imsdk.packet.DeliverySentManager;
import com.senyint.imsdk.packet.PacketReadExtension;
import com.senyint.imsdk.packet.PacketReadIQ;
import com.senyint.imsdk.packet.SimpleEventIQ;
import com.senyint.imsdk.util.PacketUtil;

/**
 * 简化smack客户端连接的帮助类<br>
 * @author hui
 *
 */
public class SmackHelper2 {
	protected static final String TAG = SmackHelper2.class.getSimpleName();

	/*****************************/
	public static boolean debugable = true ;
	
	private XMPPConnection connection = null;
	
	private ISdkConfig sdkConfig = null;
	
	private SdkHandlerListener sdkHandlerListener = null ;
	
	private ConversationManager mConversationManager =  null ;
	static {
		try {
			Class.forName("org.jivesoftware.smack.ReconnectionManager");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	private ConnectionListener mConnectionListener = new XMPPConnecionListener() {
		@Override
		public void onUserConflict() {
			handleUserConflict();
		}

		@Override
		public void connectionClosed() {
			handleConnectionClosed();
		}

		@Override
		public void connectionClosedOnError(Exception ex) {
			super.connectionClosedOnError(ex);
			handleConnectionClosedOnError(ex);
		}

		@Override
		public void reconnectionSuccessful() {
			handleReconnectionSuccessful();
		}

		@Override
		public void reconnectionFailed(Exception e) {
			handleReconnectionFailed(e);
		}
	};

	private PacketInterceptor mXMPPMessageInterceptor = new XMPPMessageInterceptor() {
		@Override
		public void interceptPacket(Packet packet) {
			super.interceptPacket(packet);
			handlePacketBeforeSent(packet);
		}
	};

	private PacketListener mXMPPMessageListener = new XMPPMessageListener() {
		@Override
		public void onHandleMessage(Message message) {
			super.onHandleMessage(message);
			handleReceivedPacket(message);
		}

		@Override
		public void sendPacket(Packet packet) throws SendPacketException {
			onSend(packet);
		}

		@Override
		public void onFeedbackServer(final String msgId) {
			this.onHandleInBackgroud(new Runnable() {
				@Override
				public void run() {
					handleFeedbackServer(msgId);
				}
			});
		}
	};

	private PacketListener mXMPPPresenceListener = new XMPPPresenceListener() {
		@Override
		public void processPacket(Packet packet) {
			super.processPacket(packet);
			handleReceivedPacket(packet);
		}
	};
	
	private PacketInterceptor mXMPPPresenceInterceptor = new XMPPPresenceInterceptor() {
		@Override
		public void interceptPacket(Packet packet) {
			super.interceptPacket(packet);
			handlePacketBeforeSent(packet);
		}
	};
	
	private PacketListener mXMPPIQListener = new XMPPIQListener() {
		@Override
		public void processPacket(Packet packet) {
			super.processPacket(packet);
			handleReceivedPacket(packet);
		}

		@Override
		public void onHandleEvent(SimpleEventIQ packet) {
			super.onHandleEvent(packet);
			handleReceivedEvent(packet);
		}
	};
	
	private PacketInterceptor mXMPPIQInterceptor = new XMPPIQInterceptor() {
		@Override
		public void interceptPacket(Packet packet) {
			super.interceptPacket(packet);
			handlePacketBeforeSent(packet);
		}
	};

	/*****************************/
	public SmackHelper2 build(ISdkConfig sdkConfig) {
		this.sdkConfig = sdkConfig;
		return this;
	}

	public boolean isAuthenticated() {
		return connection != null && connection.isAuthenticated();
	}

	public void onSend(String to, String msg) {
		if (msg == null || msg.trim().length() == 0) {
			return;
		}
		final Message message = new Message();
		if (message.getPacketID() == null) {
			message.setPacketID(Packet.nextID());
		}
		String userJID =  SdkContext.me().getUserName()+"@"+SdkContext.me().getServiceName()+"/"+SdkContext.me().getResourceName();
		message.setBody(msg);
		message.setType(Message.Type.chat);
		message.setFrom(userJID);
		message.setConversation(PacketUtil.createConversationID(SdkContext.me().getUserName(), to, null));
		message.setTo(to + "@" + sdkConfig.getServiceName() + "/"+ sdkConfig.getResourceName());
		/**
		 * 添加送达服务器的回执
		 */
		DeliverySentManager.addDeliverySentRequest(message);

		onSend(message);
	}

	public void setConnectionListener(ConnectionListener mConnectionListener) {
		this.mConnectionListener = mConnectionListener;
	}

	public void setXMPPMessageInterceptor(
			PacketInterceptor mXMPPMessageInterceptor) {
		this.mXMPPMessageInterceptor = mXMPPMessageInterceptor;
	}

	public void setXMPPMessageListener(PacketListener mXMPPMessageListener) {
		this.mXMPPMessageListener = mXMPPMessageListener;
	}

	public void setXMPPPresenceListener(PacketListener mXMPPPresenceListener) {
		this.mXMPPPresenceListener = mXMPPPresenceListener;
	}

	public void setXMPPPresenceInterceptor(
			PacketInterceptor mXMPPPresenceInterceptor) {
		this.mXMPPPresenceInterceptor = mXMPPPresenceInterceptor;
	}

	public void setXMPPIQListener(PacketListener mXMPPIQListener) {
		this.mXMPPIQListener = mXMPPIQListener;
	}

	public void setXMPPIQInterceptor(PacketInterceptor mXMPPIQInterceptor) {
		this.mXMPPIQInterceptor = mXMPPIQInterceptor;
	}

	/**
	 * send the packet
	 * 
	 * @param packet
	 */
	public void onSend(Packet packet) {
		log("onSend:" + packet.toXML());
		if (connection != null && connection.isAuthenticated()) {
			connection.sendPacket(packet);
		}
	}

	public void onConnect() {
		log("connect-:> 000000000 " + connection );
		if (connection != null && this.connection.isConnected()) {
			return;
		}
		log("connect-:> 1111111 " );
		if (connection == null) {
			createConnection();
		}

		try {
			connection.connect();
		} catch (XMPPException e) {
			e.printStackTrace();
			log("connect err-:>"+e.getMessage());
		}

	}

	public void onDisconnect() {
		if (connection != null && this.connection.isConnected()) {
			connection.disconnect(new Presence(Presence.Type.unavailable));
		}
	}

	public Integer onLogin(final String uid, final String token) {
		try {
			log("login .............:" + uid );
			onConnect();
			// Login with an invalid user
			connection.login(uid, token, sdkConfig.getResourceName());
			log("login ok,user:" + SdkContext.me().getUserName() );
			handleLoginSuccess(uid,token);
			return ISdkConfig.SUCCESS ;
		} catch (XMPPException e) {
			handleLoginFailed(e);
		} catch (Exception e) {
			handleLoginFailed(e);
		}
		return ISdkConfig.FAILED ;
	}

	/**
	 * 登录成功
	 * @param uid
	 */
	public void handleLoginSuccess(String uid,String token) {
		SdkContext.me().setUserName(uid);
		SdkContext.me().setPassword(token);
		if(sdkHandlerListener != null){
			sdkHandlerListener.handleLoginSuccess(uid,token);
		}
	}

	/**
	 * 登录失败
	 * @param e
	 */
	public void handleLoginFailed(Exception e) {
		log("handleLoginFailed-->"+e.getMessage());
		if(sdkHandlerListener != null){
			sdkHandlerListener.handleLoginFailed(e);
		}
	}

	public void onLogout() {
		try {
			if (connection != null) {
				connection.disconnect(new Presence(Presence.Type.unavailable));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private XMPPConnection createConnection() {
		log("create connection cfg 000000 .............:" );
		if (connection != null)
			return connection;
		String host = sdkConfig.getHost();
		Integer port = sdkConfig.getPort();
		log("create connection cfg 111 .............:" + host+","+port  );
		// Create the configuration for this new connection
		ConnectionConfiguration config = new ConnectionConfiguration(host, port);
		config.setCompressionEnabled(false);
		config.setSendPresence(true);
		config.setSecurityMode(SecurityMode.disabled);
		config.setSASLAuthenticationEnabled(false);
		config.setReconnectionAllowed(true);

		connection = new XMPPConnection(config);
		connection.addConnectionListener(mConnectionListener);
		connection.addPacketInterceptor(mXMPPMessageInterceptor,new PacketTypeFilter(Message.class));
		connection.addPacketListener(mXMPPMessageListener,		new PacketTypeFilter(Message.class));
		connection.addPacketListener(mXMPPPresenceListener,		new PacketTypeFilter(Presence.class));
		connection.addPacketInterceptor(mXMPPPresenceInterceptor,new PacketTypeFilter(Presence.class));
		connection.addPacketListener(mXMPPIQListener, 			new PacketTypeFilter(IQ.class));
		connection.addPacketInterceptor(mXMPPIQInterceptor,		new PacketTypeFilter(IQ.class));
		
		// for ping reply
		connection.addPacketListener(new PacketListener() {
			@Override
			public void processPacket(Packet p) {
				handleServerPing(p);
			}
		}, new PacketTypeFilter(Ping.class));
		
		mConversationManager = new ConversationManager(this.connection,null);
		log("create connection cfg .............:" + host+","+port  );
		return connection;
	}

	/**
	 * 连接关闭或者异常
	 * @param ex
	 */
	public void handleConnectionClosedOnError(Exception ex) {
		log("onConnectionClosedOnError ------------> "  );
		if(sdkHandlerListener != null){
			sdkHandlerListener.handleConnectionClosedOnError(ex);
		}
	}

	/**
	 * 连接关闭
	 */
	public void handleConnectionClosed() {
		log("onConnectionClosed ------------> "  );
		if(sdkHandlerListener != null){
			sdkHandlerListener.handleConnectionClosed();
		}
	}
	
	/**
	 * 给服务器发送回执，告之服务器已经接收到消息<br>
	 * 
	 * @param msgId
	 */
	public void handleFeedbackServer(String msgId) {
		log("handleReplyReceivedMessage ---> " + msgId );
		if(msgId == null||"null".equalsIgnoreCase(msgId)) return ;
		IQ packet = new PacketReadIQ(new PacketReadExtension(msgId));
		String userJID =  SdkContext.me().getUserName()+"@"+SdkContext.me().getServiceName()+"/"+SdkContext.me().getResourceName();
		packet.setFrom(userJID);
		onSend(packet);
	}

	/**
	 * 重连失败
	 * @param e
	 */
	public void handleReconnectionFailed(Exception e) {
		log("onReconnectionFailed ");
		if(sdkHandlerListener != null){
			sdkHandlerListener.handleReconnectionFailed(e);
		}
	}

	/**
	 * 重连成功
	 */
	public void handleReconnectionSuccessful() {
		log("onReconnectionSuccessful ");
		if(sdkHandlerListener != null){
			sdkHandlerListener.handleReconnectionSuccessful();
		}
	}

	/**
	 * 发送消息前处理(presence,iq,message)
	 * 
	 * @param packet
	 */
	public void handlePacketBeforeSent(Packet packet) {
		log("send :"+packet.toXML());
		if(sdkHandlerListener != null){
			sdkHandlerListener.handlePacketBeforeSent(packet);
		}
	}

	/**
	 * 处理接收的简单事件
	 * @param packet
	 */
	public void handleReceivedEvent(SimpleEventIQ packet) {
		log("RECV event:"+packet.toXML());
		if(sdkHandlerListener != null){
			sdkHandlerListener.handleReceivedEvent(packet);
		}
	}

	/**
	 * 处理接收到的消息<br>
	 * @param packet	message,iq,presence
	 */
	public void handleReceivedPacket(Packet packet) {
		log("RECV:"+packet.toXML());
		if(sdkHandlerListener != null){
			sdkHandlerListener.handleReceivedPacket(packet);
		}
	}

	/**
	 * 处理用户登录冲突
	 */
	public void handleUserConflict() {
		if (connection != null && this.connection.isConnected()) {
			connection.disconnect(new Presence(Presence.Type.unavailable));
			connection = null ;
		}
		if(sdkHandlerListener != null){
			sdkHandlerListener.handleUserConflict();
		}
	}
	
	/**
	 * 处理服务器ping回执
	 * @param p
	 */
	public void handleServerPing(Packet p) {
		Ping pingIQ = (Ping) p;
		log("RECV:" + pingIQ.toXML());
		IQ pongIQ = IQ.createResultIQ(pingIQ);
		connection.sendPacket(pongIQ);	
		
	}
	
	private void log(String msg) {
		if(debugable)
			System.out.println(msg);
	}

	// //////////////////////////////////////////////////
	public static void debugenable(){
		debugable = true ;
	}
	
	public static void debugdisable(){
		debugable = true ;
	}
	
	public ISdkConfig getSdkConfig() {
		return sdkConfig;
	}

	protected XMPPConnection getConnection() {
		return connection;
	}
	
	public void setSdkHandlerListener(SdkHandlerListener lisn){
		sdkHandlerListener = lisn ;
	}

	public ConversationManager getConversationManager() {
		return mConversationManager;
	}

}
